package com.kgc.storeprovider.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.kgc.basic.pojo.BOM;
import com.kgc.basic.pojo.Good;
import com.kgc.basic.util.PageInfo;
import com.kgc.basic.util.ResponseMsg;
import com.kgc.store.pojo.*;
import com.kgc.storeprovider.dao.*;
import com.kgc.storeprovider.feign.BOMFeign;
import com.kgc.storeprovider.feign.SalesCounterFeign;
import com.kgc.storeprovider.service.ProDivideService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

@Service
public class ProDivideServiceImpl implements ProDivideService {

    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private ProDivideMapper proDivideMapper;
    @Autowired
    private BOMFeign bomFeign;
    @Autowired
    private SalesCounterFeign salesCounterFeign;
    @Autowired
    private StoreGoodSummaryMapper storeGoodSummaryMapper;
    @Autowired
    private OutStoreMapper outStoreMapper;
    @Autowired
    private OutStoreDetailMapper outStoreDetailMapper;
    @Autowired
    private InStoreMapper inStoreMapper;
    @Autowired
    private InStoreDetailMapper inStoreDetailMapper;

    @Override
    public ResponseMsg getByPage(Map<String, Object> map) {
        logger.info("ProDivideServiceImpl getByPage map={}", map);
        ResponseMsg responseMsg = new ResponseMsg();
        PageHelper.startPage(Integer.parseInt(map.get("pageNow").toString()), Integer.parseInt(map.get("pageSize").toString()));
        List<ProDivide> list = proDivideMapper.getAll(map);
        logger.debug("proDivideMapper getAll list={}", list+",map"+map);
        PageHelper.clearPage();
        PageInfo<ProDivide> pageInfo = new PageInfo<>();
        if (list != null && list.size() > 0) {
            for (ProDivide proDivide : list) {
                ResponseMsg response = bomFeign.getBOMById(proDivide.getBid()+"");
                logger.debug("bomFeign.getBOMById={}", response+",id="+proDivide.getBid());
                if (response.getCode().equals("200")) {
                    ObjectMapper objectMapper = new ObjectMapper();
                    BOM bom = objectMapper.convertValue(response.getData(), BOM.class);
                    proDivide.setBname(bom.getName());
                    proDivide.setPname(bom.getProduct().getName());
                }
            }
            pageInfo.setList(list);
            pageInfo.setPageNo(Integer.parseInt(map.get("pageNow").toString()));
            pageInfo.setPageSize(Integer.parseInt(map.get("pageSize").toString()));
            pageInfo.setTotal(proDivideMapper.getCount(map));
            logger.debug("proDivideMapper getCount list={}", pageInfo.getTotal()+",map"+map);
        }
        if (pageInfo.getTotal() > 0) {
            responseMsg.setCode("200");
            responseMsg.setData(pageInfo);
        }else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }

    @Override
    public ResponseMsg add(ProDivide proDivide) {
        logger.info("ProDivideServiceImpl add proDivide={}", proDivide);
        ResponseMsg responseMsg = new ResponseMsg();
        proDivide.setCreateDate(new Date());
//        proDivide.setCreateUser("admin");
        proDivide.setUpdateDate(new Date());
//        proDivide.setUpdateUser("admin");
        proDivide.setStatus("1");
        int count = proDivideMapper.add(proDivide);
        logger.debug("proDivideMapper.add count={}", count+",proDivide"+proDivide);
        if(count==0){
            responseMsg.setCode("201");
            return responseMsg;
        }
        Map<String,Object> map = new HashMap<>();
        map.put("code",proDivide.getCode());
        map.put("updateDate",proDivide.getUpdateDate());
        map.put("updateUser",proDivide.getUpdateUser());
        Long bid = proDivide.getBid();
        BOM bom = null;
        ResponseMsg response = bomFeign.getBOMById(bid+"");
        logger.debug("bomFeign.getBOMById={}", response+",bid="+bid);
        if (response.getCode().equals("200")) {
            ObjectMapper objectMapper = new ObjectMapper();
            bom = objectMapper.convertValue(response.getData(), BOM.class);
        }
        if(bom==null){
            throw new  RuntimeException();
        }
        boolean flag = addDetail(proDivide,bom,map);
        if(flag){
            responseMsg.setCode("200");
        }else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }

    @Override
    public ResponseMsg update(ProDivide proDivide) {
        logger.info("ProDivideServiceImpl update proDivide={}", proDivide);
        ResponseMsg responseMsg = new ResponseMsg();
        proDivide.setUpdateDate(new Date());
//        proDivide.setUpdateUser("11111");
        int count = proDivideMapper.update(proDivide);
        logger.debug("proDivideMapper update count={}", count+",proDivide"+proDivide);
        if(count==0){
            responseMsg.setCode("201");
            return responseMsg;
        }
        Map<String,Object> map = new HashMap<>();
        map.put("code",proDivide.getCode());
        Long bid = proDivide.getBid();
        BOM bom = null;
        ResponseMsg response = bomFeign.getBOMById(bid+"");
        logger.debug("bomFeign.getBOMById={}", response+",bid="+bid);
        if (response.getCode().equals("200")) {
            ObjectMapper objectMapper = new ObjectMapper();
            bom = objectMapper.convertValue(response.getData(), BOM.class);
        }
        if(bom==null){
            throw new  RuntimeException();
        }
        int num = proDivideMapper.delDetail(proDivide.getCode());
        if(num==0){
            responseMsg.setCode("201");
            return responseMsg;
        }
        boolean flag = addDetail(proDivide,bom,map);
        if(flag){
            responseMsg.setCode("200");
        }else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }

    private boolean addDetail(ProDivide proDivide,BOM bom,Map<String,Object> map){
        List<Integer> sids = proDivide.getSids();
        map.put("createUser",proDivide.getCreateUser());
        map.put("createDate",proDivide.getCreateDate());
        map.put("updateUser",proDivide.getUpdateUser());
        map.put("updateDate",proDivide.getUpdateDate());
        Good good = bom.getProduct();
        map.put("gid",good.getId());
        int sid = sids.get(0);
        map.put("sid",sid);
        int nu = proDivideMapper.addDetail(map);
        logger.debug("proDivideMapper addDetail nu:{}",nu+",map"+map);
        List<Good> list = bom.getMaterial();
        if(nu==0){
            return false;
        }
        for (int i=0;i<list.size();i++){
            good = list.get(i);
            map.put("gid",good.getId());
            sid = sids.get(i+1);
            map.put("sid",sid);
            nu = proDivideMapper.addDetail(map);
            logger.debug("proDivideMapper addDetail nu:{}",nu+",map"+map);
            if(nu==0){
                return false;
            }
        }
        return true;
    }

    @Override
    public ResponseMsg delete(String code) {
        logger.info("ProDivideServiceImpl delete code={}", code);
        ResponseMsg responseMsg = new ResponseMsg();
        Map<String, Object> map = new HashMap<>();
        map.put("code", code);
        map.put("updateDate", new Date());
        map.put("updateUser", "123");
        int count = proDivideMapper.del(map);
        logger.debug("proDivideMapper.del count={}", count+",map="+map);
        if (count > 0) {
            int num = proDivideMapper.deleteDetail(map);
            logger.debug("proDivideMapper.deleteDetail num={}", num+",map="+map);
            if (num == 0) {
                responseMsg.setCode("201");
                return responseMsg;
            }
            responseMsg.setCode("200");
        }else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }

    @Override
    public ResponseMsg getByCode(String code) {
        logger.info("ProDivideServiceImpl getByCode code={}", code);
        ResponseMsg responseMsg = new ResponseMsg();
        ProDivide proDivide = proDivideMapper.getByCode(code);
        BOM bom = null;
        if (proDivide == null) {
            responseMsg.setCode("201");
            return responseMsg;
        }
        long id = proDivide.getBid();
        if (id != 0) {
            ResponseMsg response = bomFeign.getBOMById(id+"");
            logger.debug("bomFeign.getBOMById={}", response+",id="+id);
            if (response.getCode().equals("200")) {
                ObjectMapper objectMapper = new ObjectMapper();
                bom = objectMapper.convertValue(response.getData(), BOM.class);
            }
        }
        if (bom == null) {
            responseMsg.setCode("201");
            return responseMsg;
        }
        proDivide.setBom(bom);
        Map<String,Object> map = new HashMap<>();
        map.put("code", code);
        List<Integer> sids = new ArrayList<>();
        map.put("gid",bom.getProduct().getId());
        int sid = proDivideMapper.getSid(map);
        logger.debug("proDivideMapper.getSid={}", sid+",map="+map);
        if (sid == 0) {
            responseMsg.setCode("201");
            return responseMsg;
        }
        sids.add(sid);
        for (Good good : bom.getMaterial()) {
            map.put("gid",good.getId());
            sid = proDivideMapper.getSid(map);
            logger.debug("proDivideMapper.getSid={}", sid+",map="+map);
            if(sid==0){
                responseMsg.setCode("201");
            }
            sids.add(sid);
        }
        proDivide.setSids(sids);
        responseMsg.setCode("200");
        responseMsg.setData(proDivide);
        return responseMsg;
    }

    @Override
    public ResponseMsg changeStatus(String code, String status) {
        logger.info("ProDivideServiceImpl changeStatus code:{}", code);
        ResponseMsg responseMsg = new ResponseMsg();
        int count = proDivideMapper.changeStatus(code,status);
        logger.debug("proDivideMapper changeStatus count:{}", count+",code"+code);
        if(count>0){
            responseMsg.setCode("200");
        }else {
            responseMsg.setCode("201");
        }
        return responseMsg;
    }

    // 拆卸单转出库单（成品出库）
    @Override
    public OutStore createOutStoreFromProCombine(ProDivide proDivide) {
        OutStore outStore = new OutStore();
        // 1. 生成出库单号
        Map<String,Object> map = new HashMap<>();
        map.put("docType","CXCK");   // 拆卸出库
        String outCode = salesCounterFeign.addSalesCode(map).getData().toString();
        outStore.setCode(outCode);

        // 2. 填充出库单头
        outStore.setOrderDate(proDivide.getDate());
        outStore.setSourceCode(proDivide.getCode());
        outStore.setCid((int)proDivide.getUid());
        outStore.setDeptId((int)proDivide.getDid());
        outStore.setStoreManId((int)proDivide.getSkid());
        outStore.setTypeId(proDivide.getTypeId());
        outStore.setOrderTypeId(proDivide.getTypeId());
        outStore.setIsDelete(0);
        outStore.setCreateId((int)proDivide.getUid());
        outStore.setCreateName(proDivide.getCreateUser());
        outStore.setCreateDate(new Date());

        // 3. 明细：仅成品
        List<OutStoreDetail> details = new ArrayList<>();
        Good product = proDivide.getBom().getProduct();
        OutStoreDetail d = new OutStoreDetail();
        d.setOutStoreCode(outCode);
        d.setGoodId((int)product.getId());
        d.setGoodsCode(product.getCode());
        d.setGoodsName(product.getName());
        d.setCount((int)proDivide.getCount());
        d.setStoreId((int)proDivide.getSkid());
        d.setStoreName(proDivide.getSkname());

        BigDecimal price = storeGoodSummaryMapper
                .selectKcStoreGoodBySidCid(d.getStoreId(), d.getGoodId())
                .getPrice();
        d.setPrice(price);
        d.setSumPrice(price.multiply(BigDecimal.valueOf(d.getCount())));
        d.setCreateId((int)proDivide.getUid());
        d.setCreateName(proDivide.getCreateUser());
        d.setCreateDate(new Date());
        logger.debug("ProDivideServiceImpl OutStoreDetail={}",d);
        details.add(d);
        // 4. 保存
        saveOutStore(outStore, details);
        return outStore;
    }

    private void saveOutStore(OutStore outStore, List<OutStoreDetail> details) {
        int c = outStoreMapper.insertOutStore(outStore);
        if (c <= 0) throw new RuntimeException("成品出库单保存失败");
        for (OutStoreDetail d : details) {
            d.setOutStoreCode(outStore.getCode());
            if (outStoreDetailMapper.insertOutStoreDetail(d) <= 0)
                throw new RuntimeException("成品出库明细保存失败");
        }
    }

    // 拆卸单转入库单（原料入库）
    @Override
    public InStore createInStoreFromProCombine(ProDivide proDivide) {
        InStore inStore = new InStore();
        // 1. 生成入库单号
        Map<String,Object> map = new HashMap<>();
        map.put("docType","CXRK");   // 拆卸入库
        String inCode = salesCounterFeign.addSalesCode(map).getData().toString();
        inStore.setCode(inCode);

        // 2. 填充入库单头
        inStore.setOrderDate(proDivide.getDate());
        inStore.setSourceCode(proDivide.getCode());
        inStore.setPid((int)proDivide.getUid());
        inStore.setDeptId((int)proDivide.getDid());
        inStore.setStoreManId((int)proDivide.getSkid());
        inStore.setTypeId(proDivide.getTypeId());
        inStore.setOrderTypeId(proDivide.getTypeId());
        inStore.setIsDelete(0);
        inStore.setCreateId((int)proDivide.getUid());
        inStore.setCreateName(proDivide.getCreateUser());
        inStore.setCreateDate(new Date());

        // 3. 明细：循环原料
        List<InStoreDetail> details = new ArrayList<>();
        List<Good> materials = proDivide.getBom().getMaterial();
        for (int i = 0; i < materials.size(); i++) {
            Good m = materials.get(i);
            InStoreDetail d = new InStoreDetail();
            d.setInStoreCode(inCode);
            d.setGoodId((int)m.getId());
            d.setGoodsCode(m.getCode());
            d.setGoodsName(m.getName());
            d.setCount((int)proDivide.getCount());
            d.setStoreId(proDivide.getSids().get(i+1));    // sids[0] 已用于成品仓库，可依次对应原料仓库
            d.setStoreName(proDivide.getSkname());         // 如仓库名列表与 sids 一一对应，请自行调整

            BigDecimal price = storeGoodSummaryMapper
                    .selectKcStoreGoodBySidCid(d.getStoreId(), d.getGoodId())
                    .getPrice();
            d.setPrice(price);
            d.setSumPrice(price.multiply(BigDecimal.valueOf(d.getCount())));
            d.setCreateId((int)proDivide.getUid());
            d.setCreateName(proDivide.getCreateUser());
            d.setCreateDate(new Date());
            details.add(d);
        }

        // 4. 保存
        saveInStore(inStore, details);
        return inStore;
    }

    private void saveInStore(InStore inStore, List<InStoreDetail> details) {
        int c = inStoreMapper.insertInStore(inStore);
        if (c <= 0) throw new RuntimeException("原料入库单保存失败");
        for (InStoreDetail d : details) {
            d.setInStoreCode(inStore.getCode());
            if (inStoreDetailMapper.insertInStoreDetail(d) <= 0)
                throw new RuntimeException("原料入库明细保存失败");
        }
    }

}
